#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include "dtest.h"

USART_InitType USART_InitStructure_dtest_uart_cmd;
GPIO_InitType GPIO_InitStructure_dtest_uart_cmd;

uint8_t dtest_RxBuffer1[100];
__IO uint8_t dtest_TxCounter1         = 0x00;
__IO uint8_t dtest_RxCounter1         = 0x00;

uint8_t dtest_RxBuffer_256[256];
uint8_t dtest_RxCounter_256 = 0;

uint32_t dtest_value[256];
uint32_t dtest_result[256];

extern void dtest_reset_board(uint32_t case_id);
extern void dtest_ver(uint32_t case_id);
extern void get_dtest_value(uint32_t case_id);
extern void get_dtest_result(uint32_t case_id);


/* 每个测试用例的信息，包括用例名称字符串和要调用的测试函数 */
struct dtest_tc_info_item
{
    const char	*testcase_name;					/* 测试用例名称 */
    void				(*testcase_func)(uint32_t case_id); /* 测试用例函数 */
};
typedef struct dtest_tc_info_item dtest_tc_info_item_t;

/* 测试用例信息的集合，包括所有用例的信息和用例数，单板收到测试命令dtest后，会在这里找对应的测试函数 */
struct dtest_tc_info
{
    dtest_tc_info_item_t		*tc_table;
    uint16_t								tc_num;
};
typedef struct dtest_tc_info dtest_tc_info_t;

dtest_tc_info_item_t dtest_testcase_list[] = {
	{"dtest_reset_board",&dtest_reset_board},
	{"dtest_ver",&dtest_ver},
	{"get_dtest_value",&get_dtest_value},
	{"get_dtest_result",&get_dtest_result},
};

static dtest_tc_info_t g_s_tc_table_info = {dtest_testcase_list, sizeof(dtest_testcase_list)/8};


/* 查找测试命令对应的测试用例 */
dtest_tc_info_item_t *dtest_entry_1(char *casename, dtest_tc_info_t *tc_table_info)
{
    dtest_tc_info_item_t		*tc_entry;
    uint8_t									cmp_len;
    uint8_t									index;

    cmp_len = 0;
    if (casename)
    {
        cmp_len = strlen(casename);
    }

    tc_entry = 0;
    for (index = 0; index < tc_table_info->tc_num; index++)
    {
        if (cmp_len > 0)
        {
            if (memcmp(tc_table_info->tc_table[index].testcase_name, casename, cmp_len))
            {
                continue;
            }
        }

        tc_entry = &tc_table_info->tc_table[index];
        break;
    }

    return tc_entry;
}

/* 解析测试命令，并调用对应的测试函数 */
void dtest_testcase_entry(void)
{
	int space_count = 0;
	int cmd_count = 0;
	int name_count = 0;
	char cmd[16] = "";
	char casename[32] = "";
	int case_id = 0;
	int i = 0;
	
  dtest_tc_info_item_t		*tc_entry;
	
	for(i=0;i<dtest_RxCounter1-1;i++)
	{
		if((char)dtest_RxBuffer1[i] == ' ')
		{
			space_count++;
			continue;
		}
		else if(space_count == 0)
		{
			cmd[cmd_count++]=(char)dtest_RxBuffer1[i];
		}
		else if(space_count == 1)
		{
			casename[name_count++]=(char)dtest_RxBuffer1[i];
		}
		else if(space_count == 2)
		{
			case_id *= 10;
			case_id += (char)dtest_RxBuffer1[i] - '0';
		}
		else
		{
			break;
		}
	}
	
	
	if(strcmp(cmd,"dtest") != 0)
	{
		printf("other command!\n");
		return;
	}

	tc_entry = dtest_entry_1(casename, &g_s_tc_table_info);
	if (!tc_entry)
	{
		printf("can't find testcase name\n");	
		return;
	}
		
	tc_entry->testcase_func((uint32_t)(int)case_id);
}

/**
 * @brief  This function handles USARTy global interrupt request.
		串口接收到命令后会进入这个中断处理函数，PC端发出的命令要以回车（\r\n）结尾
 */
void UART_CMD_IRQHandler(void)
{
    if (USART_GetIntStatus(UART_CMD, USART_INT_RXDNE) != RESET)
    {

			/* Read one byte from the receive data register */
    	dtest_RxBuffer1[dtest_RxCounter1] = USART_ReceiveData(UART_CMD);

        if (dtest_RxBuffer1[dtest_RxCounter1] == 0x0A && dtest_RxCounter1 != 0)
        {
						if (dtest_RxBuffer1[dtest_RxCounter1-1] == 0x0D)
						{
								dtest_testcase_entry();
								dtest_RxCounter1 = 0;
								return;
						}
        }

        dtest_RxCounter1++;
    }
}

//负责收发命令的UART_CMD初始化（包含GPIOC的相关初始化）
void dtest_UART_CMD_init(void)
{
	__disable_irq();
	//初始化GPIO C和UART_CMD的时钟
	RCC_EnableAPB2PeriphClk(UART_CMD_GPIO_CLK | RCC_APB2_PERIPH_AFIO, ENABLE);
	RCC_EnableAPB1PeriphClk(UART_CMD_CLK, ENABLE);

	//GPIO初始化
	GPIO_ConfigPinRemap(GPIO_RMP2_UART5,ENABLE);

	GPIO_InitStructure_dtest_uart_cmd.Pin       = UART_CMD_RxPin;
	GPIO_InitStructure_dtest_uart_cmd.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(UART_CMD_GPIO, &GPIO_InitStructure_dtest_uart_cmd);

	GPIO_InitStructure_dtest_uart_cmd.Pin        = UART_CMD_TxPin;
	GPIO_InitStructure_dtest_uart_cmd.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure_dtest_uart_cmd.GPIO_Mode  = GPIO_Mode_AF_PP;
	GPIO_Init(UART_CMD_GPIO, &GPIO_InitStructure_dtest_uart_cmd);

	//中断初始化
	ECLIC_SetCfgNlbits(0); /* 0 bits for level, 4 bits for priority */
	/* Enable the USARTy Interrupt */
	ECLIC_SetPriorityIRQ(UART_CMD_IRQn, 1);
	ECLIC_SetTrigIRQ(UART_CMD_IRQn, ECLIC_LEVEL_TRIGGER);
	ECLIC_EnableIRQ(UART_CMD_IRQn);

	//UART_CMD初始化
	USART_InitStructure_dtest_uart_cmd.BaudRate            = 115200; /* Band rate is too high may cause data lost in this example.
	    													When system clock is 8M, the maximum band rate allowed is 38400 */
	USART_InitStructure_dtest_uart_cmd.WordLength          = USART_WL_8B;
	USART_InitStructure_dtest_uart_cmd.StopBits            = USART_STPB_1;
	USART_InitStructure_dtest_uart_cmd.Parity              = USART_PE_NO;
	USART_InitStructure_dtest_uart_cmd.HardwareFlowControl = USART_HFCTRL_NONE;
	USART_InitStructure_dtest_uart_cmd.Mode                = USART_MODE_RX | USART_MODE_TX;

	USART_Init(UART_CMD, &USART_InitStructure_dtest_uart_cmd);
	USART_ConfigInt(UART_CMD, USART_INT_RXDNE, ENABLE);
	/* Enable global interrupt */
    __enable_irq();
    USART_Enable(UART_CMD, ENABLE);

	memset(dtest_value, 0, 256*4);
	memset(dtest_result, 1, 256*4);


	printf_cmd("UART_CMD init finished!\n");
}


/**
 * @brief  printf function JUST for cmd.
 */
#ifndef printf_cmd
void printf_cmd (char *fmt, ...)
{
	char printf_cmd_buffer[256];
	memset(printf_cmd_buffer, 0, 256);
	u8 i = 0;

	va_list arg_ptr;
	va_start(arg_ptr, fmt);
	vsnprintf(printf_cmd_buffer, 256, fmt, arg_ptr);
	while ((i < 256) && printf_cmd_buffer[i])
	{
			USART_SendData(UART_CMD, (u8) printf_cmd_buffer[i++]);
			while (USART_GetFlagStatus(UART_CMD, USART_FLAG_TXDE) == RESET);
	}
	va_end(arg_ptr);
}
#endif
